home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / prntutil / gemgs13 / ps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-25  |  37.8 KB  |  1,192 lines

  1. /*
  2.  * ps.c -- Postscript scanning and copying routines.
  3.  * Copyright (C) 1992  Timothy O. Theisen
  4.  *
  5.  * Modified slightly for use with gemGS on the Atari ST by
  6.  * Tim Gallivan, 8/92
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  *   Author: Tim Theisen           Systems Programmer
  23.  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
  24.  *     UUCP: uwvax!tim             University of Wisconsin-Madison
  25.  *    Phone: (608)262-0438         1210 West Dayton Street
  26.  *      FAX: (608)262-9777         Madison, WI   53706
  27.  */
  28.  
  29. #include <stdio.h>
  30. #ifndef SEEK_SET
  31. #define SEEK_SET 0
  32. #endif
  33. #ifndef BUFSIZ
  34. #define BUFSIZ 1024
  35. #endif
  36. #include <string.h>
  37. #include <aesbind.h>
  38. #include "ps.h"
  39.  
  40. /* length calculates string length at compile time */
  41. /* can only be used with character constants */
  42. #define length(a) (sizeof(a)-1)
  43. #define iscomment(a, b)    (strncmp(a, b, length(b)) == 0)
  44. #define fprintf(a, b) (form_alert(1,"[1]["b"][OK]"))
  45.  
  46.     /* list of standard paper sizes from Adobe's PPD. */
  47.  
  48. struct documentmedia papersizes[] = {
  49.     "Letter",         612,  792,
  50.     "LetterSmall",     612,  792,
  51.     "Tabloid",         792, 1224,
  52.     "Ledger",        1224,  792,
  53.     "Legal",         612, 1008,
  54.     "Statement",     396,  612,
  55.     "Executive",     540,  720,
  56.     "A3",         842, 1190,
  57.     "A4",         595,  842,
  58.     "A4Small",         595,  842,
  59.     "A5",         420,  595,
  60.     "B4",         729, 1032,
  61.     "B5",         516,  729,
  62.     "Folio",         612,  936,
  63.     "Quarto",         610,  780,
  64.     "10x14",         720, 1008,
  65.     NULL,           0,    0
  66. };
  67.  
  68.  
  69. static char *readline();
  70.     /* Position of file just before the current line was read */
  71. static long file_position;
  72.  
  73. static char *gettextline();
  74. static char *gettext();
  75.     /* Pointer to first character after text returned by gettext */
  76. static char *next_char;
  77.  
  78. static int  isblank();
  79.  
  80. /*
  81.  *    psscan -- scan the PostScript file for document structuring comments.
  82.  *
  83.  *    This scanner is designed to retrieve the information necessary for
  84.  *    the ghostview previewer.  It will scan files that conform to any
  85.  *    version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
  86.  *    It does not really care which version of comments the file contains.
  87.  *    (The comments are largely upward compatible.)  It will scan a number
  88.  *    of non-conforming documents.  (You could have part of the document
  89.  *    conform to V2.0 and the rest conform to V3.0.  It would be similar
  90.  *    to the DC-2 1/2+, it would look funny but it can still fly.)
  91.  *
  92.  *    This routine returns a pointer to the document structure.
  93.  *    The structure contains the information relevant to previewing.
  94.  *      These include EPSF flag (to tell if the file is a encapsulated figure),
  95.  *      Page Media (for the Page Size), Bounding Box (to minimize backing
  96.  *      pixmap size or determine window size for encapsulated PostScript), 
  97.  *      Orientation of Paper (for default transformation matrix), and
  98.  *      Page Order.  The title and CreationDate are also retrieved to
  99.  *      help identify the document.
  100.  *
  101.  *      The following comments are examined:
  102.  *
  103.  *      Header section: 
  104.  *      Must start with %!PS-Adobe-.  Version numbers ignored.
  105.  *
  106.  *      %!PS-Adobe-* [EPSF-*]
  107.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  108.  *      %%CreationDate: <textline>
  109.  *      %%Orientation: Portrait|Landscape|(atend)
  110.  *      %%Pages: <uint> [<int>]|(atend)
  111.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  112.  *      %%Title: <textline>
  113.  *      %%DocumentMedia: <text> <real> <real> <real> <text> <text>
  114.  *      %%DocumentPageSizes: <text>
  115.  *      %%EndComments
  116.  *
  117.  *      Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
  118.  *            Also either the 2.0 %%DocumentPageSizes or the 3.0
  119.  *            %%DocumentMedia comments are accepted as well.
  120.  *
  121.  *      The header section ends either explicitly with %%EndComments or
  122.  *      implicitly with any line that does not begin with %X where X is
  123.  *      a not whitespace character.
  124.  *
  125.  *      If the file is encapsulated PostScript the optional Preview section
  126.  *      is next:
  127.  *
  128.  *      %%BeginPreview
  129.  *      %%EndPreview
  130.  *
  131.  *      This section explicitly begins and ends with the above comments.
  132.  *
  133.  *      Next the Defaults section for version 3 page defaults:
  134.  *
  135.  *      %%BeginDefaults
  136.  *      %%PageBoundingBox: <int> <int> <int> <int>
  137.  *      %%PageOrientation: Portrait|Landscape
  138.  *      %%PageMedia: <text>
  139.  *      %%EndDefaults
  140.  *
  141.  *      This section explicitly begins and ends with the above comments.
  142.  *
  143.  *      The prolog section either explicitly starts with %%BeginProlog or
  144.  *      implicitly with any nonblank line.
  145.  *
  146.  *      %%BeginProlog
  147.  *      %%EndProlog
  148.  *
  149.  *      The Prolog should end with %%EndProlog, however the proglog implicitly
  150.  *      ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
  151.  *
  152.  *      The Setup section is where the version 2 page defaults are found.
  153.  *      This section either explicitly begins with %%BeginSetup or implicitly
  154.  *      with any noblank line after the Prolog.
  155.  *
  156.  *      %%BeginSetup
  157.  *      %%PageBoundingBox: <int> <int> <int> <int>
  158.  *      %%PageOrientation: Portrait|Landscape
  159.  *      %%PaperSize: <text>
  160.  *      %%EndSetup
  161.  *
  162.  *      The Setup should end with %%EndSetup, however the setup implicitly
  163.  *      ends when %%Page, %%Trailer or %%EOF are encountered.
  164.  *
  165.  *      Next each page starts explicitly with %%Page and ends implicitly with
  166.  *      %%Page or %%Trailer or %%EOF.  The following comments are recognized:
  167.  *
  168.  *      %%Page: <text>
  169.  *      %%PageBoundingBox: <int> <int> <int> <int>|(atend)
  170.  *      %%PageOrientation: Portrait|Landscape
  171.  *      %%PageMedia: <text>
  172.  *      %%PaperSize: <text>
  173.  *
  174.  *      The tralier section start explicitly with %%Trailer and end with %%EOF.
  175.  *      The following comment are examined with the proper (atend) notation
  176.  *      was used in the header:
  177.  *
  178.  *      %%Trailer
  179.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  180.  *      %%Orientation: Portrait|Landscape|(atend)
  181.  *      %%Pages: <uint> [<int>]|(atend)
  182.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  183.  *      %%EOF
  184.  *
  185.  *
  186.  *  + A DC-3 received severe damage to one of its wings.  The wing was a total
  187.  *    loss.  There was no replacement readily available, so the mechanic
  188.  *    install a wing from a DC-2.
  189.  */
  190.  
  191. struct document *
  192. psscan(file)
  193.     FILE *file;
  194. {
  195.     struct document *doc;
  196.     int bb_set = NNONE;
  197.     int pages_set = NNONE;
  198.     int page_order_set = NNONE;
  199.     int orientation_set = NNONE;
  200.     int page_bb_set = NNONE;
  201.     int page_media_set = NNONE;
  202.     int preread;        /* flag which tells the readline isn't needed */
  203.     int i;
  204.     unsigned int maxpages = 0;
  205.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  206.     char text[PSLINELENGTH];    /* Temporary storage for text */
  207.     char *cp;
  208.     struct documentmedia *dmp;
  209.  
  210.     rewind(file);
  211.     if (readline(line, sizeof line, file) == NULL) {
  212.     fprintf(stderr, "Warning: empty file.\n");
  213.     return(NULL);
  214.     }
  215.  
  216.     /* Header comments */
  217.  
  218.     if (iscomment(line,"%!PS-Adobe-")) {
  219.     doc = (struct document *) malloc(sizeof(struct document));
  220.     if (doc == NULL) {
  221.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  222.         exit(-1);
  223.     }
  224.     memset(doc, 0, sizeof(struct document));
  225.     sscanf(line, "%*s %s", text);
  226.     doc->epsf = iscomment(text, "EPSF-");
  227.     doc->beginheader = file_position;
  228.     } else {
  229.     return(NULL);
  230.     }
  231.  
  232.     preread = 0;
  233.     while (preread || readline(line, sizeof line, file)) {
  234.     preread = 0;
  235.     if (iscomment(line, "%%EndComments") ||
  236.         line[0] != '%' ||
  237.         (line[1] == ' ' || line[1] == '\t' || line[1] == '\n')) {
  238.         break;
  239.     } else if (!iscomment(line, "%%")) {
  240.         /* Do nothing */
  241.     } else if (doc->title == NULL && iscomment(line+2, "Title:")) {
  242.         doc->title = gettextline(line+length("%%Title:"));
  243.     } else if (doc->date == NULL && iscomment(line+2, "CreationDate:")) {
  244.         doc->date = gettextline(line+length("%%CreationDate:"));
  245.     } else if (bb_set == NNONE && iscomment(line+2, "BoundingBox:")) {
  246.         sscanf(line+length("%%BoundingBox:"), "%s", text);
  247.         if (strcmp(text, "(atend)") == 0) {
  248.         bb_set = ATEND;
  249.         } else {
  250.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  251.                &(doc->boundingbox[LLX]),
  252.                &(doc->boundingbox[LLY]),
  253.                &(doc->boundingbox[URX]),
  254.                &(doc->boundingbox[URY])) == 4)
  255.             bb_set = 1;
  256.         else {
  257.             float fllx, flly, furx, fury;
  258.             if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  259.                    &fllx, &flly, &furx, &fury) == 4) {
  260.             bb_set = 1;
  261.             doc->boundingbox[LLX] = fllx;
  262.             doc->boundingbox[LLY] = flly;
  263.             doc->boundingbox[URX] = furx;
  264.             doc->boundingbox[URY] = fury;
  265.             if (fllx < doc->boundingbox[LLX])
  266.                 doc->boundingbox[LLX]--;
  267.             if (flly < doc->boundingbox[LLY])
  268.                 doc->boundingbox[LLY]--;
  269.             if (furx > doc->boundingbox[URX])
  270.                 doc->boundingbox[URX]++;
  271.             if (fury > doc->boundingbox[URY])
  272.                 doc->boundingbox[URY]++;
  273.             }
  274.         }
  275.         }
  276.     } else if (orientation_set == NNONE &&
  277.            iscomment(line+2, "Orientation:")) {
  278.         sscanf(line+length("%%Orientation:"), "%s", text);
  279.         if (strcmp(text, "(atend)") == 0) {
  280.         orientation_set = ATEND;
  281.         } else if (strcmp(text, "Portrait") == 0) {
  282.         doc->orientation = PORTRAIT;
  283.         orientation_set = 1;
  284.         } else if (strcmp(text, "Landscape") == 0) {
  285.         doc->orientation = LANDSCAPE;
  286.         orientation_set = 1;
  287.         }
  288.     } else if (page_order_set == NNONE && iscomment(line+2, "PageOrder:")) {
  289.         sscanf(line+length("%%PageOrder:"), "%s", text);
  290.         if (strcmp(text, "(atend)") == 0) {
  291.         page_order_set = ATEND;
  292.         } else if (strcmp(text, "Ascend") == 0) {
  293.         doc->pageorder = ASCEND;
  294.         page_order_set = 1;
  295.         } else if (strcmp(text, "Descend") == 0) {
  296.         doc->pageorder = DESCEND;
  297.         page_order_set = 1;
  298.         } else if (strcmp(text, "Special") == 0) {
  299.         doc->pageorder = SPECIAL;
  300.         page_order_set = 1;
  301.         }
  302.     } else if (pages_set == NNONE && iscomment(line+2, "Pages:")) {
  303.         sscanf(line+length("%%Pages:"), "%s", text);
  304.         if (strcmp(text, "(atend)") == 0) {
  305.         pages_set = ATEND;
  306.         } else {
  307.         switch (sscanf(line+length("%%Pages:"), "%d %d",
  308.                    &maxpages, &i)) {
  309.             case 2:
  310.             if (page_order_set == NNONE) {
  311.                 if (i == -1) {
  312.                 doc->pageorder = DESCEND;
  313.                 page_order_set = 1;
  314.                 } else if (i == 0) {
  315.                 doc->pageorder = SPECIAL;
  316.                 page_order_set = 1;
  317.                 } else if (i == 1) {
  318.                 doc->pageorder = ASCEND;
  319.                 page_order_set = 1;
  320.                 }
  321.             }
  322.             case 1:
  323.             doc->pages = (struct page *) calloc(maxpages,
  324.                             sizeof(struct page));
  325.             if (doc->pages == NULL) {
  326.                 fprintf(stderr,
  327.                     "Fatal Error: Dynamic memory exhausted.\n");
  328.                 exit(-1);
  329.             }
  330.         }
  331.         }
  332.     } else if (doc->nummedia == NNONE &&
  333.            iscomment(line+2, "DocumentMedia:")) {
  334.         float w, h;
  335.         doc->media = (struct documentmedia *)
  336.              malloc(sizeof (struct documentmedia));
  337.         if (doc->media == NULL) {
  338.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  339.         exit(-1);
  340.         }
  341.         doc->media[0].name = gettext(line+length("%%DocumentMedia:"));
  342.         if (doc->media[0].name != NULL) {
  343.         if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  344.             doc->media[0].width = w + 0.5;
  345.             doc->media[0].height = h + 0.5;
  346.         }
  347.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  348.             doc->nummedia = 1;
  349.         else
  350.             free(doc->media[0].name);
  351.         }
  352.         preread=1;
  353.         while (readline(line, sizeof line, file) &&
  354.            iscomment(line, "%%+")) {
  355.         doc->media = (struct documentmedia *)
  356.                  realloc(doc->media,
  357.                      (doc->nummedia+1)*
  358.                      sizeof (struct documentmedia));
  359.         if (doc->media == NULL) {
  360.             fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  361.             exit(-1);
  362.         }
  363.         doc->media[doc->nummedia].name = gettext(line+length("%%+"));
  364.         if (doc->media[doc->nummedia].name != NULL) {
  365.             if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  366.             doc->media[doc->nummedia].width = w + 0.5;
  367.             doc->media[doc->nummedia].height = h + 0.5;
  368.             }
  369.             if (doc->media[doc->nummedia].width != 0 &&
  370.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  371.             else
  372.             free(doc->media[doc->nummedia].name);
  373.         }
  374.         }
  375.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  376.     } else if (doc->nummedia == NNONE &&
  377.            iscomment(line+2, "DocumentPaperSizes:")) {
  378.  
  379.         doc->media = (struct documentmedia *)
  380.              malloc(sizeof (struct documentmedia));
  381.         if (doc->media == NULL) {
  382.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  383.         exit(-1);
  384.         }
  385.         doc->media[0].name = gettext(line+length("%%DocumentPaperSizes:"));
  386.         if (doc->media[0].name != NULL) {
  387.         doc->media[0].width = 0;
  388.         doc->media[0].height = 0;
  389.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  390.             /* Note: Paper size comment uses down cased paper size
  391.              * name.  Case insensitive compares are only used for
  392.              * PaperSize comments.
  393.              */
  394.             if (strcasecmp(doc->media[0].name, dmp->name) == 0) {
  395.             free(doc->media[0].name);
  396.             doc->media[0].name =
  397.                 (char *)malloc(strlen(dmp->name)+1);
  398.             if (doc->media[0].name == NULL) {
  399.                 fprintf(stderr,
  400.                     "Fatal Error: Dynamic memory exhausted.\n");
  401.                 exit(-1);
  402.             }
  403.             strcpy(doc->media[0].name, dmp->name);
  404.             doc->media[0].width = dmp->width;
  405.             doc->media[0].height = dmp->height;
  406.             break;
  407.             }
  408.         }
  409.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  410.             doc->nummedia = 1;
  411.         else
  412.             free(doc->media[0].name);
  413.         }
  414.         while (cp = gettext(next_char)) {
  415.         doc->media = (struct documentmedia *)
  416.                  realloc(doc->media,
  417.                      (doc->nummedia+1)*
  418.                      sizeof (struct documentmedia));
  419.         if (doc->media == NULL) {
  420.             fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  421.             exit(-1);
  422.         }
  423.         doc->media[doc->nummedia].name = cp;
  424.         doc->media[doc->nummedia].width = 0;
  425.         doc->media[doc->nummedia].height = 0;
  426.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  427.             /* Note: Paper size comment uses down cased paper size
  428.              * name.  Case insensitive compares are only used for
  429.              * PaperSize comments.
  430.              */
  431.             if (strcasecmp(doc->media[doc->nummedia].name,
  432.                    dmp->name) == 0) {
  433.             free(doc->media[doc->nummedia].name);
  434.             doc->media[doc->nummedia].name =
  435.                 (char *)malloc(strlen(dmp->name)+1);
  436.             if (doc->media[doc->nummedia].name == NULL) {
  437.                 fprintf(stderr,
  438.                     "Fatal Error: Dynamic memory exhausted.\n");
  439.                 exit(-1);
  440.             }
  441.             strcpy(doc->media[doc->nummedia].name, dmp->name);
  442.             doc->media[doc->nummedia].name = dmp->name;
  443.             doc->media[doc->nummedia].width = dmp->width;
  444.             doc->media[doc->nummedia].height = dmp->height;
  445.             break;
  446.             }
  447.         }
  448.         if (doc->media[doc->nummedia].width != 0 &&
  449.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  450.         else
  451.             free(doc->media[doc->nummedia].name);
  452.         }
  453.         preread=1;
  454.         while (readline(line, sizeof line, file) &&
  455.            iscomment(line, "%%+")) {
  456.         next_char = line + length("%%+");
  457.         while (cp = gettext(next_char)) {
  458.             doc->media = (struct documentmedia *)
  459.                  realloc(doc->media,
  460.                      (doc->nummedia+1)*
  461.                      sizeof (struct documentmedia));
  462.             if (doc->media == NULL) {
  463.             fprintf(stderr,
  464.                 "Fatal Error: Dynamic memory exhausted.\n");
  465.             exit(-1);
  466.             }
  467.             doc->media[doc->nummedia].name = cp;
  468.             doc->media[doc->nummedia].width = 0;
  469.             doc->media[doc->nummedia].height = 0;
  470.             for (dmp=papersizes; dmp->name != NULL; dmp++) {
  471.             /* Note: Paper size comment uses down cased paper size
  472.              * name.  Case insensitive compares are only used for
  473.              * PaperSize comments.
  474.              */
  475.             if (strcasecmp(doc->media[doc->nummedia].name,
  476.                    dmp->name) == 0) {
  477.                 doc->media[doc->nummedia].width = dmp->width;
  478.                 doc->media[doc->nummedia].height = dmp->height;
  479.                 break;
  480.             }
  481.             }
  482.             if (doc->media[doc->nummedia].width != 0 &&
  483.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  484.             else
  485.             free(doc->media[doc->nummedia].name);
  486.         }
  487.         }
  488.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  489.     }
  490.     }
  491.  
  492.     if (iscomment(line, "%%EndComments")) readline(line, sizeof line, file);
  493.     doc->endheader = file_position;
  494.  
  495.     /* Optional Preview comments for encapsulated PostScript files */ 
  496.  
  497.     while (isblank(line) && readline(line, sizeof line, file)) {}
  498.  
  499.     if (doc->epsf && iscomment(line, "%%BeginPreview")) {
  500.     doc->beginpreview = file_position;
  501.     while (readline(line, sizeof line, file) &&
  502.            !iscomment(line, "%%EndPreview")) {}
  503.     readline(line, sizeof line, file);
  504.     doc->endpreview = file_position;
  505.     }
  506.  
  507.     /* Page Defaults for Version 3.0 files */
  508.  
  509.     while (isblank(line) && readline(line, sizeof line, file)) {}
  510.  
  511.     if (iscomment(line, "%%BeginDefaults")) {
  512.     doc->begindefaults = file_position;
  513.     while (readline(line, sizeof line, file) &&
  514.            !iscomment(line, "%%EndDefaults")) {
  515.         if (!iscomment(line, "%%")) {
  516.         /* Do nothing */
  517.         } else if (doc->default_page_orientation == NNONE &&
  518.         iscomment(line+2, "PageOrientation:")) {
  519.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  520.         if (strcmp(text, "Portrait") == 0) {
  521.             doc->default_page_orientation = PORTRAIT;
  522.         } else if (strcmp(text, "Landscape") == 0) {
  523.             doc->default_page_orientation = LANDSCAPE;
  524.         }
  525.         } else if (page_media_set == NNONE &&
  526.                iscomment(line+2, "PageMedia:")) {
  527.         cp = gettext(line+length("%%PageMedia:"));
  528.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  529.             if (strcmp(cp, dmp->name) == 0) {
  530.             doc->default_page_media = dmp;
  531.             page_media_set = 1;
  532.             break;
  533.             }
  534.         }
  535.         free(cp);
  536.         } else if (page_bb_set == NNONE &&
  537.                iscomment(line+2, "PageBoundingBox:")) {
  538.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  539.                &(doc->default_page_boundingbox[LLX]),
  540.                &(doc->default_page_boundingbox[LLY]),
  541.                &(doc->default_page_boundingbox[URX]),
  542.                &(doc->default_page_boundingbox[URY])) == 4)
  543.             page_bb_set = 1;
  544.         else {
  545.             float fllx, flly, furx, fury;
  546.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  547.                    &fllx, &flly, &furx, &fury) == 4) {
  548.             page_bb_set = 1;
  549.             doc->default_page_boundingbox[LLX] = fllx;
  550.             doc->default_page_boundingbox[LLY] = flly;
  551.             doc->default_page_boundingbox[URX] = furx;
  552.             doc->default_page_boundingbox[URY] = fury;
  553.             if (fllx < doc->default_page_boundingbox[LLX])
  554.                 doc->default_page_boundingbox[LLX]--;
  555.             if (flly < doc->default_page_boundingbox[LLY])
  556.                 doc->default_page_boundingbox[LLY]--;
  557.             if (furx > doc->default_page_boundingbox[URX])
  558.                 doc->default_page_boundingbox[URX]++;
  559.             if (fury > doc->default_page_boundingbox[URY])
  560.                 doc->default_page_boundingbox[URY]++;
  561.             }
  562.         }
  563.         }
  564.     }
  565.     readline(line, sizeof line, file);
  566.     doc->enddefaults = file_position;
  567.     }
  568.  
  569.     /* Document Prolog */
  570.  
  571.     while (isblank(line) && readline(line, sizeof line, file)) {}
  572.  
  573.     if (!iscomment(line, "%%BeginSetup") && !iscomment(line, "%%Page:") &&
  574.     !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  575.     doc->beginprolog = file_position;
  576.     preread = 1;
  577.  
  578.     while ((preread || readline(line, sizeof line, file)) &&
  579.            !iscomment(line, "%%EndProlog") &&
  580.            !iscomment(line, "%%BeginSetup") &&
  581.            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  582.            !iscomment(line, "%%EOF")) {
  583.         preread = 0;
  584.  
  585.     }
  586.     if (iscomment(line, "%%EndProlog")) {
  587.         readline(line, sizeof line, file);
  588.     }
  589.     doc->endprolog = file_position;
  590.     }
  591.  
  592.     /* Document Setup,  Page Defaults found here for Version 2 files */
  593.  
  594.     while (isblank(line) && readline(line, sizeof line, file)) {}
  595.  
  596.     if (!iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  597.     !iscomment(line, "%%EOF")) {
  598.     doc->beginsetup = file_position;
  599.     preread = 1;
  600.     while ((preread || readline(line, sizeof line, file)) &&
  601.            !iscomment(line, "%%EndSetup") && !iscomment(line, "%%Page:") &&
  602.            !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  603.         preread = 0;
  604.         if (!iscomment(line, "%%")) {
  605.         /* Do nothing */
  606.         } else if (doc->default_page_orientation == NNONE &&
  607.         iscomment(line+2, "PageOrientation:")) {
  608.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  609.         if (strcmp(text, "Portrait") == 0) {
  610.             doc->default_page_orientation = PORTRAIT;
  611.         } else if (strcmp(text, "Landscape") == 0) {
  612.             doc->default_page_orientation = LANDSCAPE;
  613.         }
  614.         } else if (page_media_set == NNONE &&
  615.                iscomment(line+2, "PaperSize:")) {
  616.         cp = gettext(line+length("%%PaperSize:"));
  617.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  618.             /* Note: Paper size comment uses down cased paper size
  619.              * name.  Case insensitive compares are only used for
  620.              * PaperSize comments.
  621.              */
  622.             if (strcasecmp(cp, dmp->name) == 0) {
  623.             doc->default_page_media = dmp;
  624.             page_media_set = 1;
  625.             break;
  626.             }
  627.         }
  628.         free(cp);
  629.         } else if (page_bb_set == NNONE &&
  630.                iscomment(line+2, "PageBoundingBox:")) {
  631.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  632.                &(doc->default_page_boundingbox[LLX]),
  633.                &(doc->default_page_boundingbox[LLY]),
  634.                &(doc->default_page_boundingbox[URX]),
  635.                &(doc->default_page_boundingbox[URY])) == 4)
  636.             page_bb_set = 1;
  637.         else {
  638.             float fllx, flly, furx, fury;
  639.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  640.                    &fllx, &flly, &furx, &fury) == 4) {
  641.             page_bb_set = 1;
  642.             doc->default_page_boundingbox[LLX] = fllx;
  643.             doc->default_page_boundingbox[LLY] = flly;
  644.             doc->default_page_boundingbox[URX] = furx;
  645.             doc->default_page_boundingbox[URY] = fury;
  646.             if (fllx < doc->default_page_boundingbox[LLX])
  647.                 doc->default_page_boundingbox[LLX]--;
  648.             if (flly < doc->default_page_boundingbox[LLY])
  649.                 doc->default_page_boundingbox[LLY]--;
  650.             if (furx > doc->default_page_boundingbox[URX])
  651.                 doc->default_page_boundingbox[URX]++;
  652.             if (fury > doc->default_page_boundingbox[URY])
  653.                 doc->default_page_boundingbox[URY]++;
  654.             }
  655.         }
  656.         }
  657.     }
  658.     if (iscomment(line, "%%EndSetup")) {
  659.         readline(line, sizeof line, file);
  660.     }
  661.     doc->endsetup = file_position;
  662.     }
  663.  
  664.     /* Individual Pages */
  665.  
  666.     while (isblank(line) && readline(line, sizeof line, file)) {}
  667.  
  668.     while (iscomment(line, "%%Page:")) {
  669.     if (maxpages == 0) {
  670.         maxpages = 1;
  671.         doc->pages = (struct page *) calloc(maxpages, sizeof(struct page));
  672.         if (doc->pages == NULL) {
  673.         fprintf(stderr,
  674.             "Fatal Error: Dynamic memory exhausted.\n");
  675.         exit(-1);
  676.         }
  677.     }
  678.     if (doc->numpages == maxpages) {
  679.         maxpages++;
  680.         doc->pages = (struct page *)
  681.              realloc(doc->pages, maxpages*sizeof (struct page));
  682.         if (doc->pages == NULL) {
  683.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  684.         exit(-1);
  685.         }
  686.     }
  687.     memset(&(doc->pages[doc->numpages]), 0, sizeof(struct page));
  688.     page_bb_set = NNONE;
  689.     doc->pages[doc->numpages].label = gettext(line+length("%%Page:"));
  690.     doc->pages[doc->numpages].begin = file_position;
  691.     while (readline(line, sizeof line, file) &&
  692.            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  693.            !iscomment(line, "%%EOF")) {
  694.         if (!iscomment(line, "%%")) {
  695.         /* Do nothing */
  696.         } else if (doc->pages[doc->numpages].orientation == NNONE &&
  697.         iscomment(line+2, "PageOrientation:")) {
  698.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  699.         if (strcmp(text, "Portrait") == 0) {
  700.             doc->pages[doc->numpages].orientation = PORTRAIT;
  701.         } else if (strcmp(text, "Landscape") == 0) {
  702.             doc->pages[doc->numpages].orientation = LANDSCAPE;
  703.         }
  704.         } else if (doc->pages[doc->numpages].media == NULL &&
  705.                iscomment(line+2, "PageMedia:")) {
  706.         cp = gettext(line+length("%%PageMedia:"));
  707.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  708.             if (strcmp(cp, dmp->name) == 0) {
  709.             doc->pages[doc->numpages].media = dmp;
  710.             break;
  711.             }
  712.         }
  713.         free(cp);
  714.         } else if (doc->pages[doc->numpages].media == NULL &&
  715.                iscomment(line+2, "PaperSize:")) {
  716.         cp = gettext(line+length("%%PaperSize:"));
  717.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  718.             /* Note: Paper size comment uses down cased paper size
  719.              * name.  Case insensitive compares are only used for
  720.              * PaperSize comments.
  721.              */
  722.             if (strcasecmp(cp, dmp->name) == 0) {
  723.             doc->pages[doc->numpages].media = dmp;
  724.             break;
  725.             }
  726.         }
  727.         free(cp);
  728.         } else if ((page_bb_set == NNONE || page_bb_set == ATEND) &&
  729.                iscomment(line+2, "PageBoundingBox:")) {
  730.         sscanf(line+length("%%PageBoundingBox:"), "%s", text);
  731.         if (strcmp(text, "(atend)") == 0) {
  732.             page_bb_set = ATEND;
  733.         } else {
  734.             if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  735.                 &(doc->pages[doc->numpages].boundingbox[LLX]),
  736.                 &(doc->pages[doc->numpages].boundingbox[LLY]),
  737.                 &(doc->pages[doc->numpages].boundingbox[URX]),
  738.                 &(doc->pages[doc->numpages].boundingbox[URY])) == 4)
  739.             if (page_bb_set == NNONE) page_bb_set = 1;
  740.             else {
  741.             float fllx, flly, furx, fury;
  742.             if (sscanf(line+length("%%PageBoundingBox:"),
  743.                    "%f %f %f %f",
  744.                    &fllx, &flly, &furx, &fury) == 4) {
  745.                 if (page_bb_set == NNONE) page_bb_set = 1;
  746.                 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
  747.                 doc->pages[doc->numpages].boundingbox[LLY] = flly;
  748.                 doc->pages[doc->numpages].boundingbox[URX] = furx;
  749.                 doc->pages[doc->numpages].boundingbox[URY] = fury;
  750.                 if (fllx <
  751.                     doc->pages[doc->numpages].boundingbox[LLX])
  752.                 doc->pages[doc->numpages].boundingbox[LLX]--;
  753.                 if (flly <
  754.                     doc->pages[doc->numpages].boundingbox[LLY])
  755.                 doc->pages[doc->numpages].boundingbox[LLY]--;
  756.                 if (furx >
  757.                     doc->pages[doc->numpages].boundingbox[URX])
  758.                 doc->pages[doc->numpages].boundingbox[URX]++;
  759.                 if (fury >
  760.                     doc->pages[doc->numpages].boundingbox[URY])
  761.                 doc->pages[doc->numpages].boundingbox[URY]++;
  762.             }
  763.             }
  764.         }
  765.         }
  766.     }
  767.     doc->pages[doc->numpages].end = file_position;
  768.     doc->numpages++;
  769.     }
  770.  
  771.     /* Document Trailer */
  772.  
  773.     doc->begintrailer = file_position;
  774.  
  775.     preread = 1;
  776.     while ((preread || readline(line, sizeof line, file)) &&
  777.        !iscomment(line, "%%EOF")) {
  778.     preread = 0;
  779.     if (!iscomment(line, "%%")) {
  780.         /* Do nothing */
  781.     } else if (bb_set == ATEND && iscomment(line+2, "BoundingBox:")) {
  782.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  783.                &(doc->boundingbox[LLX]),
  784.                &(doc->boundingbox[LLY]),
  785.                &(doc->boundingbox[URX]),
  786.                &(doc->boundingbox[URY])) != 4) {
  787.         float fllx, flly, furx, fury;
  788.         if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  789.                &fllx, &flly, &furx, &fury) == 4) {
  790.             doc->boundingbox[LLX] = fllx;
  791.             doc->boundingbox[LLY] = flly;
  792.             doc->boundingbox[URX] = furx;
  793.             doc->boundingbox[URY] = fury;
  794.             if (fllx < doc->boundingbox[LLX])
  795.             doc->boundingbox[LLX]--;
  796.             if (flly < doc->boundingbox[LLY])
  797.             doc->boundingbox[LLY]--;
  798.             if (furx > doc->boundingbox[URX])
  799.             doc->boundingbox[URX]++;
  800.             if (fury > doc->boundingbox[URY])
  801.             doc->boundingbox[URY]++;
  802.         }
  803.         }
  804.     } else if (orientation_set == ATEND &&
  805.            iscomment(line+2, "Orientation:")) {
  806.         sscanf(line+length("%%Orientation:"), "%s", text);
  807.         if (strcmp(text, "Portrait") == 0) {
  808.         doc->orientation = PORTRAIT;
  809.         } else if (strcmp(text, "Landscape") == 0) {
  810.         doc->orientation = LANDSCAPE;
  811.         }
  812.     } else if (page_order_set == ATEND && iscomment(line+2, "PageOrder:")) {
  813.         sscanf(line+length("%%PageOrder:"), "%s", text);
  814.         if (strcmp(text, "Ascend") == 0) {
  815.         doc->pageorder = ASCEND;
  816.         } else if (strcmp(text, "Descend") == 0) {
  817.         doc->pageorder = DESCEND;
  818.         } else if (strcmp(text, "Special") == 0) {
  819.         doc->pageorder = SPECIAL;
  820.         }
  821.     } else if (pages_set == ATEND && iscomment(line+2, "Pages:")) {
  822.         if (sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
  823.         if (page_order_set == NNONE) {
  824.             if (i == -1) doc->pageorder = DESCEND;
  825.             else if (i == 0) doc->pageorder = SPECIAL;
  826.             else if (i == 1) doc->pageorder = ASCEND;
  827.         }
  828.         }
  829.     }
  830.     }
  831.     if (iscomment(line, "%%EOF")) {
  832.     readline(line, sizeof line, file);
  833.     }
  834.     doc->endtrailer = file_position;
  835.  
  836.     return doc;
  837. }
  838.  
  839. /*
  840.  *    psfree -- free dynamic storage associated with document structure.
  841.  */
  842.  
  843. void
  844. psfree(doc)
  845.     struct document *doc;
  846. {
  847.     int i;
  848.  
  849.     if (doc) {
  850.     for (i=0; i<doc->numpages; i++) {
  851.         if (doc->pages[i].label) free(doc->pages[i].label);
  852.     }
  853.     for (i=0; i<doc->nummedia; i++) {
  854.         if (doc->media[i].name) free(doc->media[i].name);
  855.     }
  856.     if (doc->title) free(doc->title);
  857.     if (doc->date) free(doc->date);
  858.     if (doc->pages) free(doc->pages);
  859.     if (doc->media) free(doc->media);
  860.     free(doc);
  861.     }
  862. }
  863.  
  864. /*
  865.  * gettextine -- skip over white space and return the rest of the line.
  866.  *               If the text begins with '(' return the text string
  867.  *         using gettext().
  868.  */
  869.  
  870. static char *
  871. gettextline(line)
  872.     char *line;
  873. {
  874.     char *cp;
  875.  
  876.     while (*line && (*line == ' ' || *line == '\t')) line++;
  877.     if (*line == '(') {
  878.     return gettext(line);
  879.     } else {
  880.     if (strlen(line) == 0) return NULL;
  881.     cp = (char *) malloc(strlen(line));
  882.     if (cp == NULL) {
  883.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  884.         exit(-1);
  885.     }
  886.     strncpy(cp, line, strlen(line)-1);
  887.     cp[strlen(line)-1] = '\0';
  888.     return cp;
  889.     }
  890. }
  891.  
  892. /*
  893.  *    gettext -- return the next text string on the line.
  894.  *           return NULL if nothing is present.
  895.  *                 NOTE: next_char is modified by this routine.
  896.  */
  897.  
  898. static char *
  899. gettext(line)
  900.     char *line;
  901. {
  902.     char text[PSLINELENGTH];    /* Temporary storage for text */
  903.     char *cp;
  904.     int quoted=0;
  905.  
  906.     while (*line && (*line == ' ' || *line == '\t')) line++;
  907.     cp = text;
  908.     if (*line == '(') {
  909.     int level = 0;
  910.     quoted=1;
  911.     line++;
  912.     while (*line && !(*line == ')' && level == 0 )) {
  913.         if (*line == '\\') {
  914.         if (*(line+1) == 'n') {
  915.             *cp++ = '\n';
  916.             line += 2;
  917.         } else if (*(line+1) == 'r') {
  918.             *cp++ = '\r';
  919.             line += 2;
  920.         } else if (*(line+1) == 't') {
  921.             *cp++ = '\t';
  922.             line += 2;
  923.         } else if (*(line+1) == 'b') {
  924.             *cp++ = '\b';
  925.             line += 2;
  926.         } else if (*(line+1) == 'f') {
  927.             *cp++ = '\f';
  928.             line += 2;
  929.         } else if (*(line+1) == '\\') {
  930.             *cp++ = '\\';
  931.             line += 2;
  932.         } else if (*(line+1) == '(') {
  933.             *cp++ = '(';
  934.             line += 2;
  935.         } else if (*(line+1) == ')') {
  936.             *cp++ = ')';
  937.             line += 2;
  938.         } else if (*(line+1) >= '0' && *(line+1) <= '9') {
  939.             if (*(line+2) >= '0' && *(line+2) <= '9') {
  940.             if (*(line+3) >= '0' && *(line+3) <= '9') {
  941.                 *cp++ = ((*(line+1) - '0')*8 + *(line+2) - '0')*8 +
  942.                     *(line+3) - '0';
  943.                 line += 4;
  944.             } else {
  945.                 *cp++ = (*(line+1) - '0')*8 + *(line+2) - '0';
  946.                 line += 3;
  947.             }
  948.             } else {
  949.             *cp++ = *(line+1) - '0';
  950.             line += 2;
  951.             }
  952.         } else {
  953.             line++;
  954.             *cp++ = *line++;
  955.         }
  956.         } else if (*line == '(') {
  957.         level++;
  958.         *cp++ = *line++;
  959.         } else if (*line == ')') {
  960.         level--;
  961.         *cp++ = *line++;
  962.         } else {
  963.         *cp++ = *line++;
  964.         }
  965.     }
  966.     } else {
  967.     while (*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
  968.         *cp++ = *line++;
  969.     }
  970.     *cp = '\0';
  971.     next_char = line;
  972.     if (!quoted && strlen(text) == 0) return NULL;
  973.     cp = (char *) malloc(strlen(text)+1);
  974.     if (cp == NULL) {
  975.     fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  976.     exit(-1);
  977.     }
  978.     strcpy(cp, text);
  979.     return cp;
  980. }
  981.  
  982. /*
  983.  *    readline -- Read the next line in the postscript file.
  984.  *                  Automatically skip over data (as indicated by
  985.  *                  %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  986.  *            comments.)
  987.  *            Also, skip over included documents (as indicated by
  988.  *            %%BeginDocument/%%EndDocument comments.)
  989.  *            Note: file_position is modified by this routine.
  990.  */
  991.  
  992. static char *
  993. readline(line, size, fp)
  994.     char *line;
  995.     int size;
  996.     FILE *fp;
  997. {
  998.     char text[PSLINELENGTH];    /* Temporary storage for text */
  999.     char *cp;
  1000.     unsigned int num;
  1001.     int i;
  1002.     char buf[BUFSIZ];
  1003.     long position;
  1004.  
  1005.     position = ftell(fp);
  1006.     cp = fgets(line, size, fp);
  1007.     if (iscomment(line, "%%BeginDocument:")) {
  1008.     while (readline(line, size, fp) && !iscomment(line, "%%EndDocument")) {}
  1009.     cp = readline(line, size, fp);
  1010.     } else if (iscomment(line, "%%BeginData:")) {
  1011.     text[0] = '\0';
  1012.     if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
  1013.         if (strcmp(text, "Lines") == 0) {
  1014.         for (i=0; i < num; i++) {
  1015.             cp = fgets(line, size, fp);
  1016.         }
  1017.         } else {
  1018.         while (num > BUFSIZ) {
  1019.             fread(buf, sizeof (char), BUFSIZ, fp);
  1020.             num -= BUFSIZ;
  1021.         }
  1022.         fread(buf, sizeof (char), num, fp);
  1023.         }
  1024.     }
  1025.     while (readline(line, size, fp) && !iscomment(line, "%%EndData")) {}
  1026.     cp = readline(line, size, fp);
  1027.     } else if (iscomment(line, "%%BeginBinary:")) {
  1028.     if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1029.         while (num > BUFSIZ) {
  1030.         fread(buf, sizeof (char), BUFSIZ, fp);
  1031.         num -= BUFSIZ;
  1032.         }
  1033.         fread(buf, sizeof (char), num, fp);
  1034.     }
  1035.     while (readline(line, size, fp) && !iscomment(line, "%%EndBinary")) {}
  1036.     cp = readline(line, size, fp);
  1037.     }
  1038.     file_position = position;
  1039.     return cp;
  1040. }
  1041.  
  1042. /*
  1043.  *    pscopy -- copy lines of Postscript from a section of one file
  1044.  *          to another file.
  1045.  *                Automatically switch to binary copying whenever
  1046.  *                %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1047.  *          comments are encountered.
  1048.  */
  1049.  
  1050. void
  1051. pscopy(from, to, begin, end)
  1052.     FILE *from;
  1053.     FILE *to;
  1054.     long begin;            /* set negative to avoid initial seek */
  1055.     long end;
  1056. {
  1057.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1058.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1059.     unsigned int num;
  1060.     int i;
  1061.     char buf[BUFSIZ];
  1062.  
  1063.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1064.     while (ftell(from) < end) {
  1065.  
  1066.     fgets(line, sizeof line, from);
  1067.     fputs(line, to);
  1068.  
  1069.     if (iscomment(line, "%%BeginData:")) {
  1070.         text[0] = '\0';
  1071.         if (sscanf(line+length("%%BeginData:"),
  1072.                "%d %*s %s", &num, text) >= 1) {
  1073.         if (strcmp(text, "Lines") == 0) {
  1074.             for (i=0; i < num; i++) {
  1075.             fgets(line, sizeof line, from);
  1076.             fputs(line, to);
  1077.             }
  1078.         } else {
  1079.             while (num > BUFSIZ) {
  1080.             fread(buf, sizeof (char), BUFSIZ, from);
  1081.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1082.             num -= BUFSIZ;
  1083.             }
  1084.             fread(buf, sizeof (char), num, from);
  1085.             fwrite(buf, sizeof (char), num, to);
  1086.         }
  1087.         }
  1088.     } else if (iscomment(line, "%%BeginBinary:")) {
  1089.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1090.         while (num > BUFSIZ) {
  1091.             fread(buf, sizeof (char), BUFSIZ, from);
  1092.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1093.             num -= BUFSIZ;
  1094.         }
  1095.         fread(buf, sizeof (char), num, from);
  1096.         fwrite(buf, sizeof (char), num, to);
  1097.         }
  1098.     }
  1099.     }
  1100. }
  1101.  
  1102. /*
  1103.  *    pscopyuntil -- copy lines of Postscript from a section of one file
  1104.  *               to another file until a particular comment is reached.
  1105.  *                     Automatically switch to binary copying whenever
  1106.  *                     %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1107.  *               comments are encountered.
  1108.  */
  1109.  
  1110. char *
  1111. pscopyuntil(from, to, begin, end, comment)
  1112.     FILE *from;
  1113.     FILE *to;
  1114.     long begin;            /* set negative to avoid initial seek */
  1115.     long end;
  1116. #if NeedFunctionPrototypes
  1117.     const
  1118. #endif
  1119.     char *comment;
  1120. {
  1121.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1122.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1123.     unsigned int num;
  1124.     int comment_length;
  1125.     int i;
  1126.     char buf[BUFSIZ];
  1127.     char *cp;
  1128.  
  1129.     comment_length = strlen(comment);
  1130.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1131.     while (ftell(from) < end) {
  1132.  
  1133.     fgets(line, sizeof line, from);
  1134.  
  1135.     /* iscomment cannot be used here,
  1136.      * because comment_length is not known at compile time. */
  1137.     if (strncmp(line, comment, comment_length) == 0) {
  1138.         cp = (char *) malloc(strlen(line)+1);
  1139.         if (cp == NULL) {
  1140.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  1141.         exit(-1);
  1142.         }
  1143.         strcpy(cp, line);
  1144.         return cp;
  1145.     }
  1146.     fputs(line, to);
  1147.     if (iscomment(line, "%%BeginData:")) {
  1148.         text[0] = '\0';
  1149.         if (sscanf(line+length("%%BeginData:"),
  1150.                "%d %*s %s", &num, text) >= 1) {
  1151.         if (strcmp(text, "Lines") == 0) {
  1152.             for (i=0; i < num; i++) {
  1153.             fgets(line, sizeof line, from);
  1154.             fputs(line, to);
  1155.             }
  1156.         } else {
  1157.             while (num > BUFSIZ) {
  1158.             fread(buf, sizeof (char), BUFSIZ, from);
  1159.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1160.             num -= BUFSIZ;
  1161.             }
  1162.             fread(buf, sizeof (char), num, from);
  1163.             fwrite(buf, sizeof (char), num, to);
  1164.         }
  1165.         }
  1166.     } else if (iscomment(line, "%%BeginBinary:")) {
  1167.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1168.         while (num > BUFSIZ) {
  1169.             fread(buf, sizeof (char), BUFSIZ, from);
  1170.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1171.             num -= BUFSIZ;
  1172.         }
  1173.         fread(buf, sizeof (char), num, from);
  1174.         fwrite(buf, sizeof (char), num, to);
  1175.         }
  1176.     }
  1177.     }
  1178.     return NULL;
  1179. }
  1180.  
  1181. /*
  1182.  *    isblank -- determine whether the line contains nothing but whitespace.
  1183.  */
  1184.  
  1185. static int
  1186. isblank(line)
  1187.     char *line;
  1188. {
  1189.     while (*line == ' ' || *line == '\t') line++;
  1190.     return *line == '\n';
  1191. }
  1192.